package xyz.wadewhy.basicstest.designPatterns.SingletonModel;

/**
 * 懒汉，线程不安全
 */
class LazySingleton {
    private static LazySingleton instance;

    /**
     * 构造函数私有
     */
    private LazySingleton() {
    }

    /**
     * 线程不安全
     * 1.构造函数私有，只能通过getInstance获取
     * 2.能够达到延迟加载，但是在并发情况下，会出问题
     *
     * @return LazySingleton
     */
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

/**
 * 懒汉，线程安全
 */
class LazySingletonSyn {
    private static LazySingletonSyn instance;

    /**
     * 构造函数私有
     */
    private LazySingletonSyn() {
    }

    /**
     * 线程安全
     * 1.构造函数私有，只能通过getInstance获取
     * 2.能够达到延迟加载，synchronized加锁，效率不高
     *
     * @return LazySingletonSyn
     */
    public static synchronized LazySingletonSyn getInstance() {
        if (instance == null) {
            instance = new LazySingletonSyn();
        }
        return instance;
    }
}

/**
 * 饿汉
 */
class NoLazySingleton {
    private static NoLazySingleton instance = new NoLazySingleton();

    /**
     * 构造函数私有
     */
    private NoLazySingleton() {
    }

    /**
     * 线程安全 基于classloader
     * 1.构造函数私有，只能通过getInstance获取
     * 2.不能够达到延迟加载，浪费内存
     */
    public static synchronized NoLazySingleton getInstance() {
        return instance;
    }
}

/**
 * 双重检查 推荐使用
 * 利用 volatile
 */
class DuplicationSingleton {
    private volatile static DuplicationSingleton singleton;

    /**
     * 构造函数私有
     */
    private DuplicationSingleton() {
    }

    /**
     * 双重检验
     * volatile 不能去掉
     *
     * @return
     */
    public static DuplicationSingleton getInstance() {
        if (singleton == null) {
            synchronized (DuplicationSingleton.class) {
                if (singleton == null) {
                    singleton = new DuplicationSingleton();
                }
            }
        }
        return singleton;
    }
}

/**
 * 使用静态内部类 推荐使用
 */
class StaticSingleton {
    private static class SingletonHolder {
        private static final StaticSingleton INSTANCE = new StaticSingleton();
    }

    private StaticSingleton() {
    }

    public static StaticSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

class TestDemo {
    public static void main(String[] args) {
        LazySingleton instance1 = LazySingleton.getInstance();
        LazySingleton instance2 = LazySingleton.getInstance();
        System.out.println(instance1 + "[----]" + instance2 + "[----]" + (instance1.equals(instance2)));
        testVolatile();
    }

    public static void testVolatile() {
        System.err.println(DuplicationSingleton.getInstance().equals(DuplicationSingleton.getInstance()));
    }
}
